<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index2</title>
</head>
<body>

<form onsubmit="return false">
    <textarea name="websocketMessage" style="height: 300px; width: 300px"></textarea>
    <input type="button" value="发生消息" onclick="$scope.sendMessage('data',this.form.websocketMessage.value)">
    <textarea id="responseText" style="height: 300px; width: 300px"></textarea>
    <input type="button" value="清空内容" onclick="document.getElementById('responseText').value=''">
</form>
</body>
<script type="text/javascript">
    let $scope = {};
    let localIP = "localhost";
    let localPort = "7000"
    let channelPath = "/channel";

    if (window.WebSocket) {

        let wsUrl = 'ws://' + localIP + ':' + localPort + channelPath; // ws地址
        let ws; // webSocket对象

        // 心跳重连机制
        let lockReconnect = false; // 避免重复链接
        let tryConn; // 重试连接

        let clientId; // 认证后客户端ID
        let token = "123456789"; // 令牌登录后获取


        // 创建websocket链接
        $scope.createWebSocket = function (wsUrl) {
            try {
                ws = new WebSocket(wsUrl);
                //初始化webSocket连接函数
                $scope.webSocketInit();
            } catch (e) {
                console.log('初始化websocket异常');
                //重连函数
                $scope.webSocketReconnect(wsUrl);
            }
        };
        // 初始化方法
        $scope.webSocketInit = function () {
            // 连接关闭函数
            ws.onclose = function () {
                let rt = document.getElementById("responseText");
                rt.value = rt.value + "\n" + "连接已关闭..."
                console.log("连接已关闭...");
                $scope.webSocketReconnect(wsUrl)//如果连接关闭则重连
            };
            // 连接错误函数
            ws.onerror = function () {
                let rt = document.getElementById("responseText");
                rt.value = rt.value + "\n" + "连接错误..."
                console.log("连接错误...");
                $scope.webSocketReconnect(wsUrl)//如果连接错误则重连
            };
            // 连接建立,登录认证
            ws.onopen = function () {
                let rt = document.getElementById("responseText");
                rt.value = "连接开启了,发送认证..."

                let authMessage = $scope.buildAuthMsg(token);
                console.log("发送认证", authMessage)
                ws.send(authMessage);// webSocket业务订阅——可以有多个业务
            };

            // 业务订阅成功后接受服务端推送消息
            ws.onmessage = function (evt) {
                let rt = document.getElementById("responseText");

                let responseMessage = JSON.parse(evt.data);
                console.log('接收到消息', responseMessage);
                if (responseMessage.cmd === "auth") {
                    if (responseMessage.data === "success") {
                        rt.value = rt.value + "\n" + "认证成功";
                        console.log("认证成功");
                        clientId = responseMessage.clientInfo.clientId;
                        console.log("心跳检测启动");
                        $scope.heartCheck.start();// 认证成功发生心跳检测
                    } else {
                        rt.value = rt.value + "\n" + "认证失败";
                        console.log("认证失败");
                    }
                } else if (responseMessage.cmd === "pong") {
                } else {
                    rt.value = rt.value + "\n" + evt.data;
                    // 接收一次后台推送的消息，即进行一次心跳检测重置
                    // onopen连接上，auth通过后，就开始start定时，如果在定时时间范围内，onmessage获取到了服务端非auth和ping，就重置reset倒计时，
                    // $scope.heartCheck.reset();
                    // console.log("心跳检测重置")
                }
            };
        };

        // websocket重连方法
        $scope.webSocketReconnect = function (url) {
            if (lockReconnect) {
                return;
            }
            lockReconnect = true;
            console.log("socket 连接断开，正在尝试重新建立连接");
            // 3秒后重试一次，设置延迟器只会调用一次，避免请求过多
            tryConn && clearTimeout(tryConn);
            tryConn = setTimeout(function () {
                $scope.createWebSocket(url);
                lockReconnect = false;
            }, 3000);
        };

        // 发送消息到服务器
        $scope.sendMessage = function (cmd, msg) {
            //先判断socket是否创建,消息是否为空
            if (!ws && cmd !== "" && msg !== "") {
                return;
            }
            // ws连接是否打开
            if (ws.readyState === WebSocket.OPEN) {
                let dataMessage = $scope.buildRequestMsg(cmd, msg);
                ws.send(dataMessage);
                console.log("发送data", dataMessage)
            } else {
                alert("连接没有开启");
                $scope.webSocketReconnect(wsUrl);
            }
        }

        // 心跳检测
        $scope.heartCheck = {
            timeout: 10000,// 多少秒执行心跳检测
            timeoutObj: null,// 心跳检测对象

            // 重置心跳检测
            reset: function () {
                this.stop();
                this.start();
            },

            // 启动心跳检测
            start: function () {
                this.timeoutObj = setInterval(function () {
                    let heatMessage = $scope.buildPingMsg();
                    // 启动心跳
                    console.log("发送心跳", heatMessage)
                    ws.send(heatMessage);
                }, this.timeout);
            },
            // 停止心跳检测
            stop: function () {
                setInterval(this.timeoutObj);
            },

        };

        // 构建auth msg
        $scope.buildAuthMsg = function (token) {
            return JSON.stringify({
                "clientInfo": {
                    "token": token
                },
                "cmd": "auth"
            });
        }
        // 构建ping msg
        $scope.buildPingMsg = function () {
            return JSON.stringify({
                "clientInfo": {
                    "clientId": clientId,
                    "token": token
                },
                "cmd": "ping"
            });
        }
        // 构建data msg
        $scope.buildRequestMsg = function (cmd, msg) {
            return JSON.stringify({
                "clientInfo": {
                    "clientId": clientId,
                    "token": token
                },
                "cmd": cmd,
                "data": msg
            });
        }

        $scope.createWebSocket(wsUrl);

    } else {
        alert("您的浏览器不支持 WebSocket!");
    }

</script>
</html>